// We have a lot of c-types in here, stop warning about their names!
#![allow(non_camel_case_types)]

use std::ffi::{c_char, CStr};

use poker_lib::{Counter, PokerCard, PokerCards, Suit};
use serde::{Deserialize, Serialize};
use spades_lib::{
    ai::{ai_bid, ai_play},
    round::Round,
    score::RoundResult,
    table::Table,
    turn::{TurnCard, TurnPlay},
    utils::Utils,
};
use texas_lib::{TexasCards, TexasType};
use gin_rummy_lib::cards::GinRummyCards;
// use std::os::raw::{c_char, c_float, c_int};

#[no_mangle]
pub extern "C" fn rs_GinRummyCards_new() -> *mut GinRummyCards {
    let gcs = GinRummyCards::new();
    Box::into_raw(Box::new(gcs))
}

#[no_mangle]
pub extern "C" fn rs_GinRummyCards_free(p_pcs: *mut GinRummyCards) {
    if !p_pcs.is_null() {
        unsafe {
            let _ = Box::from_raw(p_pcs);
        };
    }
}

#[no_mangle]
pub extern "C" fn rs_GinRummyCards_sort(
    p_pcs: *mut GinRummyCards,
    p_out: *mut u8,
) -> i8 {
    if p_pcs.is_null() {
        return -1;
    }
    let ret: i8;
    // 取结构
    let mut ps = unsafe { Box::from_raw(p_pcs) };
    // 要求传入足够的32字节的数据缓冲区
    let outs = unsafe { std::slice::from_raw_parts_mut(p_out, 32usize) };

    ps.sort(); 
    let mut idx = 0usize;
    // 有效的out数据格式：
    // suit长度 card1 card2...
    // number长度 card1 card2...
    // ...
    // 长度32足够了
    outs[idx] = ps.cards.cards.len() as u8;
    idx += 1;
    for v in &ps.sort_cards_suit {
        outs[idx] = v.to_u8();
        idx += 1;
    }
    outs[idx] = ps.cards.cards.len() as u8;
    idx += 1;
    for v in &ps.sort_cards_number {
        outs[idx] = v.to_u8();
        idx += 1;
    }
    // 返回out数据有效长度
    ret = idx as i8;
    std::mem::forget(ps);
    return ret;
}

#[no_mangle]
pub extern "C" fn rs_GinRummyCards_assign(
    p_pcs: *mut GinRummyCards,
    p_data: *const u16,
    data_len: usize,
    freeze: u8,
    p_out: *mut u8,
) -> i8 {
    if p_pcs.is_null() || p_data.is_null() || data_len == 0 {
        return -1;
    }
    let ret: i8;
    // 取结构
    let mut ps = unsafe { Box::from_raw(p_pcs) };
    // 取数据
    let slice = unsafe { std::slice::from_raw_parts(p_data, data_len as usize) };
    // 要求传入足够的32字节的数据缓冲区
    let outs = unsafe { std::slice::from_raw_parts_mut(p_out, 32usize) };

    match ps.assign(slice, freeze != 0) {
        Ok(n) => {
            let mut idx = 0usize;
            // 有效的out数据格式：
            // deadwood分数
            // deadwood长度 deadwood1 deadwood2 ...
            // meld1长度 meld1_1 meld1_2 ...
            // meld2长度 meld2_1 meld2_2...
            // ...
            // 长度32足够了
            // best deadwood value...
            outs[idx] = n;
            idx += 1;
            // best deadwood list...
            outs[idx] = ps.best_deadwood.len() as u8;
            idx += 1;
            for p in &ps.best_deadwood {
                outs[idx] = p.to_u8();
                idx += 1;
            }
            // melds list...
            for v in &ps.best_melds {
                outs[idx] = v.len() as u8;
                idx += 1;
                for p in v {
                    outs[idx] = p.to_u8();
                    idx += 1;
                }
            }
            // 返回out数据有效长度
            ret = idx as i8;
        }
        Err(_) => {
            // println!("{:?}", e);
            ret = -1;
        }
    }
    std::mem::forget(ps);
    return ret;
}

// 在堆上分配一个rust结构PokerCards，返回给c
// 由于含有vec字段，所以是透明结构，c中没有对应结构
#[no_mangle]
pub extern "C" fn rs_PokerCards_new() -> *mut PokerCards {
    let pcs: PokerCards = PokerCards::new();
    Box::into_raw(Box::new(pcs))
}

// 控制权归还给rust，rust在离开作用域时会释放内存
#[no_mangle]
pub extern "C" fn rs_PokerCards_free(p_pcs: *mut PokerCards) {
    if !p_pcs.is_null() {
        unsafe {
            let _ = Box::from_raw(p_pcs);
        };
    }
}

// 将unsigned short列表assign到PokerCards
#[no_mangle]
pub extern "C" fn rs_PokerCards_assign(
    p_pcs: *mut PokerCards,
    p_data: *const u16,
    data_len: usize,
) -> i8 {
    if p_pcs.is_null() || p_data.is_null() || data_len == 0 {
        return -1;
    }
    let ret: i8;
    // 取结构
    let mut ps = unsafe { Box::from_raw(p_pcs) };
    // 取数据
    let slice = unsafe { std::slice::from_raw_parts(p_data, data_len as usize) };
    match ps.assign(slice) {
        Ok(n) => {
            ret = n as i8;
        }
        Err(_) => {
            ret = -1;
        }
    }
    println!("{}", ps);
    std::mem::forget(ps);
    return ret;
}

#[repr(C)]
pub struct CardBuffer {
    data: *mut PokerCard,
    len: usize,
}

#[no_mangle]
pub extern "C" fn rs_PokerCards_get_cards(p_pcs: *mut PokerCards) -> CardBuffer {
    // 取结构
    let ps = unsafe { Box::from_raw(p_pcs) };
    let buf = ps.cards.clone().into_boxed_slice();
    let len = buf.len();
    let data: *mut PokerCard = Box::into_raw(buf) as _;
    // std::mem::forget(data);
    std::mem::forget(ps);
    CardBuffer { data, len }
}

#[no_mangle]
pub extern "C" fn rs_CardBuffer_free(buf: CardBuffer) {
    let s = unsafe { std::slice::from_raw_parts_mut(buf.data, buf.len) };
    let ps = s.as_mut_ptr();
    unsafe {
        let _ = Box::from_raw(ps);
    };
}

#[no_mangle]
pub extern "C" fn rs_PokerCards_get_counter(p_stu: *mut PokerCards, s: Suit) -> *mut Counter {
    if p_stu.is_null() {
        return std::ptr::null::<Counter>() as *mut _;
    }
    unsafe { &mut ((*p_stu)[s]) as *mut Counter }
}

#[no_mangle]
pub extern "C" fn rs_Counter_new(s: Suit) -> *mut Counter {
    let pcs: Counter = Counter::new(s);
    Box::into_raw(Box::new(pcs))
}

#[no_mangle]
pub extern "C" fn rs_Counter_free(p_counter: *mut Counter) {
    if !p_counter.is_null() {
        unsafe {
            let _ = Box::from_raw(p_counter);
        };
    }
}

#[no_mangle]
pub extern "C" fn rs_PokerCard_new(n: u16) -> *mut PokerCard {
    let pcs = PokerCard::from_spades_n(n);
    match pcs {
        Ok(p) => Box::into_raw(Box::new(p)),
        Err(_) => std::ptr::null::<PokerCard>() as *mut _,
    }
}

#[no_mangle]
pub extern "C" fn rs_PokerCard_free(p_poker: *mut PokerCard) {
    if !p_poker.is_null() {
        unsafe {
            let _ = Box::from_raw(p_poker);
        };
    }
}

// 德州扑克接口
#[no_mangle]
pub extern "C" fn rs_TexasCards_new() -> *mut TexasCards {
    let pcs = TexasCards::new();
    Box::into_raw(Box::new(pcs))
}

#[no_mangle]
pub extern "C" fn rs_TexasCards_free(p_poker: *mut TexasCards) {
    if !p_poker.is_null() {
        unsafe {
            let _ = Box::from_raw(p_poker);
        };
    }
}

#[no_mangle]
pub extern "C" fn rs_TexasCards_assign(
    p_pcs: *mut TexasCards,
    p_data: *const u16,
    data_len: usize,
) -> i8 {
    if p_pcs.is_null() || p_data.is_null() || data_len == 0 {
        return -1;
    }
    let ret: i8;
    // 取结构
    let mut ps = unsafe { Box::from_raw(p_pcs) };
    // 取数据
    let slice = unsafe { std::slice::from_raw_parts(p_data, data_len as usize) };
    match ps.assign(slice) {
        Ok(n) => {
            ret = n as i8;
        }
        Err(_) => {
            ret = -1;
        }
    }
    println!("{}", ps);
    std::mem::forget(ps);
    return ret;
}

#[repr(C)]
pub struct TexasCardBuffer {
    cardbuf: CardBuffer,
    texas: TexasType,
    score: u64,
}

#[no_mangle]
pub extern "C" fn rs_TexasCards_get_best(p_pcs: *mut TexasCards) -> TexasCardBuffer {
    // 取结构
    let ps = unsafe { Box::from_raw(p_pcs) };
    let buf = ps.best.clone().into_boxed_slice();
    let len = buf.len();
    let data: *mut PokerCard = Box::into_raw(buf) as _;
    let texas = ps.texas;
    let score = ps.score;
    // std::mem::forget(data);
    std::mem::forget(ps);
    TexasCardBuffer {
        cardbuf: CardBuffer { data, len },
        texas,
        score,
    }
}

#[no_mangle]
pub extern "C" fn rs_TexasCardBuffer_free(buf: TexasCardBuffer) {
    let s = unsafe { std::slice::from_raw_parts_mut(buf.cardbuf.data, buf.cardbuf.len) };
    let ps = s.as_mut_ptr();
    unsafe {
        let _ = Box::from_raw(ps);
    };
}

// spades接口
#[repr(C)]
#[derive(Serialize, Deserialize,Debug, Default)]
pub struct SpadesCardBuffer {
    pub cards: [u16; 13],
    pub cards_len: usize,
}

#[repr(C)]
#[derive(Serialize, Deserialize,Debug, Default)]
pub struct SpadesSeat {
    pub bid: i16,
    pub blind_nil: u8,
    pub cards: SpadesCardBuffer,
}

#[repr(C)]
#[derive(Serialize, Deserialize,Debug, Default)]
pub struct SpadesTurnCard {
    pub seat_id: usize,
    pub card: u16,
}

#[repr(C)]
#[derive(Serialize, Deserialize,Debug, Default)]
pub struct SpadesTurnPlay {
    pub turn_cards: [SpadesTurnCard; 4],
    pub turn_cards_len: usize,
    pub max_seat_id: usize,
    pub leading_id: usize,
}

#[repr(C)]
#[derive(Serialize, Deserialize,Debug, Default)]
pub struct SpadesTurnPlays {
    pub turn_plays: [SpadesTurnPlay; 13],
    pub turns_len: usize,
}

#[repr(C)]
#[derive(Serialize, Deserialize,Debug, Default)]
pub struct SpadesRound {
    pub seats: [SpadesSeat; 4],
    pub turns: SpadesTurnPlays,
    pub banker: i8,
    pub spades_break: u8,
    pub current_seat_id: usize,
}

#[repr(C)]
#[derive(Serialize, Deserialize,Debug, Default)]
pub struct SpadesTable {
    pub match_score: [i16; 2],
    pub total_bags: [i16; 2],
    pub round_count: usize,
    pub mode: i16,
    pub final_score: i16,
    pub limit_bag: i16,
    pub score_trick: i16,
    pub score_bag: i16,
    pub score_nil: i16,
    pub score_blind_nil: i16,
    pub score_bag_penalty: i16,
    pub score_lose: i16,
    pub joker: i16,
}

#[no_mangle]
pub extern "C" fn rs_SpadesRound_new() -> *mut SpadesRound {
    let pcs: SpadesRound = Default::default();
    Box::into_raw(Box::new(pcs))
}

#[no_mangle]
pub extern "C" fn rs_SpadesRound_from_json(spades_round: *mut SpadesRound, json_data: *const c_char) {
    let c_str = unsafe { CStr::from_ptr(json_data) };
    let json_str = c_str.to_str().expect("Failed to convert C string to Rust string");
    let spades_round_ref: &mut SpadesRound = unsafe { &mut *spades_round };

    let result : Result<SpadesRound,serde_json::Error> = serde_json::from_str(json_str);
    match result {
        Ok(parsed_data) => {
            *spades_round_ref = parsed_data;
            }
        Err(err) => {
            eprintln!("Error parsing SpadesRound JSON: {}", err);
        }
    }
}
#[no_mangle]
pub extern "C" fn rs_SpadesRound_free(p_pcs: *mut SpadesRound) {
    if !p_pcs.is_null() {
        unsafe {
            let _ = Box::from_raw(p_pcs);
        };
    }
}

#[no_mangle]
pub extern "C" fn rs_SpadesTable_new() -> *mut SpadesTable {
    let pcs: SpadesTable = Default::default();
    Box::into_raw(Box::new(pcs))
}

#[no_mangle]
pub extern "C" fn rs_SpadesTable_from_json(spades_table: *mut SpadesTable, json_data: *const c_char) {
    let c_str = unsafe { CStr::from_ptr(json_data) };
    let json_str = c_str.to_str().expect("Failed to convert C string to Rust string");
    let spades_round_ref: &mut SpadesTable = unsafe { &mut *spades_table };

    let result : Result<SpadesTable,serde_json::Error> = serde_json::from_str(json_str);
    match result {
        Ok(parsed_data) => {
            *spades_round_ref = parsed_data;
            }
        Err(err) => {
            eprintln!("Error parsing SpadesRound JSON: {}", err);
        }
    }
}

#[no_mangle]
pub extern "C" fn rs_SpadesTable_free(p_pcs: *mut SpadesTable) {
    if !p_pcs.is_null() {
        unsafe {
            let _ = Box::from_raw(p_pcs);
        };
    }
}

fn assign_spades_rt(pr: &SpadesRound, pt: &SpadesTable, cround: &mut Round, ctable: &mut Table) {
    cround.banker = pr.banker;
    cround.spades_break = pr.spades_break != 0;
    cround.current_seat_id = pr.current_seat_id;

    // 赋值seats
    for i in 0..4 {
        let sst = &pr.seats[i];
        let dst = &mut cround.seats[i];
        if sst.bid >= 0 {
            dst.bid = Some(sst.bid);
        } else {
            dst.bid = None;
        }
        dst.blind_nil = sst.blind_nil != 0;
        for j in 0..sst.cards.cards_len {
            dst.cards
                .add(PokerCard::from_spades_n(sst.cards.cards[j]).unwrap());
        }
    }

    // 赋值turns
    for i in 0..pr.turns.turns_len {
        let stpl = &pr.turns.turn_plays[i];
        let mut dtpl = TurnPlay::new(stpl.leading_id);
        dtpl.max_seat_id = stpl.max_seat_id;
        dtpl.leading_id = stpl.leading_id;
        for j in 0..stpl.turn_cards_len {
            dtpl.turn_cards.push(TurnCard {
                seat_id: stpl.turn_cards[j].seat_id,
                card: PokerCard::from_spades_n(stpl.turn_cards[j].card).unwrap(),
            });
        }
        let tcl = dtpl.turn_cards.len();
        cround.turns.push(dtpl);
        if tcl == 4 {
            cround.turn_end(i, true);
        }
    }

    // 赋值tables
    let mut rr = RoundResult::new();
    rr.round_number = pt.round_count as i32;
    rr.teams[0].total_bags = pt.total_bags[0];
    rr.teams[1].total_bags = pt.total_bags[1];
    rr.teams[0].match_score = pt.match_score[0];
    rr.teams[1].match_score = pt.match_score[1];
    ctable.rounds.push(rr);
    ctable.mode = pt.mode;
    ctable.final_score = pt.final_score;
    ctable.limit_bag = pt.limit_bag;
    ctable.score_trick = pt.score_trick;
    ctable.score_bag = pt.score_bag;
    ctable.score_nil = pt.score_nil;
    ctable.score_blind_nil = pt.score_blind_nil;
    ctable.score_bag_penalty = pt.score_bag_penalty;
    ctable.score_lose = pt.score_lose;
    ctable.joker = pt.joker;
}

fn check_bid_spades_rt(cround: &SpadesRound) -> i16 {
    let leader_id = Utils::get_next_player_id(cround.banker as usize);
    let current_seat_id = cround.current_seat_id;
    //校验 前面玩家的叫牌结果
    let mut temp_seat_id = leader_id;
    while temp_seat_id != current_seat_id {
        let dst = &cround.seats[temp_seat_id];
        if dst.bid < 0 {
            println!(
                "bid param error,seat {} not bid,but request bid for seat {},leader is {},code {}",
                temp_seat_id, current_seat_id, leader_id, -101
            );
            return -101;
        }
        temp_seat_id = Utils::get_next_player_id(temp_seat_id);
    }
    // 校验手牌数量
    let dst = &cround.seats[current_seat_id];
    let cards = &dst.cards;
    if cards.cards_len != 13 {
        println!(
            "bid param error,seat {} card's length is not 13 ,code {}",
            current_seat_id, -102
        );
        return -102;
    }
    //校验手牌的牌值
    for v in cards.cards {
        if !check_card_value(v) {
            println!(
                "bid param error,seat {}request bid but card value is not support  {},code {}",
                current_seat_id, v, -103
            );
            return -103;
        }
    }
    // 校验回合顺序
    if cround.turns.turns_len > 0 {
        println!(
            "bid param error,seat {}request bid after turn play,leader is {},code {}",
            current_seat_id, leader_id, -104
        );
        return -104;
    }
    return 1;
}

#[no_mangle]
pub extern "C" fn rs_SpadesAi_bid(p_r: *mut SpadesRound, p_t: *mut SpadesTable) -> i16 {
    // 取结构
    let pr = unsafe { Box::from_raw(p_r) };
    let pt = unsafe { Box::from_raw(p_t) };

    let result = std::panic::catch_unwind(|| {
        let bid;
        let mut cround = Round::new();
        let mut ctable = Table::new();
        let error_code = check_bid_spades_rt(&pr);
        if error_code < 0 {
            std::mem::forget(pr);
            std::mem::forget(pt);
            return error_code;
        }
        assign_spades_rt(&pr, &pt, &mut cround, &mut ctable);
        std::mem::forget(pr);
        std::mem::forget(pt);
        bid = ai_bid(cround.current_seat_id, &mut ctable, &mut cround);
        // println!("{:#?}", bid);
        bid
    });
    if result.is_ok() {
        result.unwrap()
    } else {
        -1
    }
}

fn check_play_spades_rt(cround: &SpadesRound) -> i16 {
    let current_seat_id = cround.current_seat_id;
    // 校验玩家bid的结果
    for i in 0..4 {
        let dst = &cround.seats[i];
        //校验每个玩家是否都已经bid
        if dst.bid < 0 {
            println!(
                "play param error,seat {} not bid,but request play card for seat {},code {}",
                i, current_seat_id, -201
            );
            return -201;
        }
    }
    let cur_seat = &cround.seats[current_seat_id];
    //回合数校验
    let turn_cnt = cround.turns.turns_len;
    if turn_cnt < 1 {
        println!("play param error,turns_len should be at least 1",);
        return -202;
    }
    //检查turns中的每个turn的牌值是否合法
    for i in 0..turn_cnt {
        let turn = &cround.turns.turn_plays[i];
        let out_cards = &turn.turn_cards;
        let out_cards_len = turn.turn_cards_len;
        //turn_cards_len包含的card是否合法
        for j in 0..out_cards_len {
            let out_card = &out_cards[j];
            //校验card是否合法
            if !check_card_value(out_card.card) {
                println!(
                    "play param error,seat {} already played  a error card {} in this turn {},code {}",
                    out_card.seat_id, out_card.card, cround.turns.turns_len, -203
                );
                return -203;
            }
            //校验是否已经出过牌
            if i == turn_cnt - 1 && out_card.seat_id == current_seat_id {
                println!(
                    "play param error,seat {} already played {:?} in this turn,but request play card in same turn {},code {}",
                     current_seat_id,out_card,cround.turns.turns_len,-204
                );
                return -204;
            }
        }
    }

    //检查手牌和turn回合数是否合法
    let cur_hand_len = cur_seat.cards.cards_len;
    if turn_cnt + cur_hand_len - 1 != 13 || cur_hand_len > 13 {
        println!(
            "play param error,seat {} card's count is {} , but turn index is {} ,expect card count {} ,code {}",
            current_seat_id,
            cur_hand_len,
            turn_cnt,
            13 - turn_cnt + 1,
            -205
        );
        return -205;
    }

    let dst = &cround.seats[current_seat_id];
    let cards = &dst.cards.cards;
    //校验当前手牌的牌值
    for i in 0..cur_hand_len {
        let v = cards[i];
        if !check_card_value(v) {
            println!(
                "play param error,seat {}request play but card value is not support  {},code {}",
                current_seat_id, v, -206
            );
            return -206;
        }
    }
    //校验 前面玩家的出牌结果
    let cur_turn = &cround.turns.turn_plays[cround.turns.turns_len - 1];
    let out_cards = &cur_turn.turn_cards;
    let leader_id = cur_turn.leading_id;
    let mut temp_seat_id = leader_id;
    while temp_seat_id != current_seat_id {
        let mut has_play = false;
        for out_cards in out_cards {
            if out_cards.seat_id == temp_seat_id {
                has_play = true;
                break;
            }
        }
        if !has_play {
            println!(
                "play param error,seat {} not play in this turn,but request play card for seat {},code {}",
                temp_seat_id, current_seat_id,-207
            );
            return -207;
        }
        temp_seat_id = Utils::get_next_player_id(temp_seat_id);
    }

    return 1;
}

fn check_card_value(v: u16) -> bool {
    match v {
        1..=54 | 102..=116 | 202..=214 | 302..=314 | 402..=414 => true,
        _ => false,
    }
}

#[no_mangle]
pub extern "C" fn rs_SpadesAi_play(p_r: *mut SpadesRound, p_t: *mut SpadesTable) -> i16 {
    // 取结构
    let pr = unsafe { Box::from_raw(p_r) };
    let pt = unsafe { Box::from_raw(p_t) };
    let result = std::panic::catch_unwind(|| {
        let card;
        let mut cround = Round::new();
        let mut ctable = Table::new();
        let error_code = check_play_spades_rt(&pr);
        if error_code < 0 {
            std::mem::forget(pr);
            std::mem::forget(pt);
            return error_code;
        }
        assign_spades_rt(&pr, &pt, &mut cround, &mut ctable);
        std::mem::forget(pr);
        std::mem::forget(pt);
        cround.make_cards_can();
        card = ai_play(cround.current_seat_id, &mut ctable, &mut cround);
        card.to_spades_n()
    });
    if result.is_ok() {
        result.unwrap()
    } else {
        -1
    }
}
